using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using ZoneFiveSoftware.Common.Data.Fitness;
using FilteredStatistics.Data;

namespace FilteredStatistics.Common.Controller
{
    abstract class FilterCriteriaFacade : IPluginSerializable, IFilterCriteria, IEnumerable<INamedZone>
    {
        protected FilterCriteriaFacade()
        {
            NamedZonedListChanged += new PropertyChangedEventHandler(OnNamedZonedListChanged);
        }

        void OnNamedZonedListChanged(object sender, PropertyChangedEventArgs e)
        {
            BuildConcreteNamedZones();
        }

#region IFilterCriteria Members

        public abstract Guid ReferenceId { get; }
        public abstract IActivity Activity { set; }
        public abstract String DisplayName { get; }
        public abstract List<object> NamedZones { get; }
        public abstract bool IsTemplateOnly { get; }
        public abstract bool IsMainViewOnly { get; }
        public abstract bool IsSerializable { get; }
        public abstract void SerializeCriteria(Stream stream);
        public abstract UInt16 DataVersion { get; }
        public abstract object DeserializeCriteria(Stream stream, UInt16 version);

        public virtual object TemplateCompatibleCriteria
        {
            get { return this; }
        }

        public virtual object OnSelectedInList(object previousSelection)
        {
            return this;
        }

        public virtual bool ValidateConsistency()
        {
            return true;
        }

        public event PropertyChangedEventHandler NamedZonedListChanged;

#endregion

#region IEnumerable<INamedZone> Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ConcreteNamedZones.GetEnumerator();
        }

        public IEnumerator<INamedZone> GetEnumerator()
        {
            return ConcreteNamedZones.GetEnumerator();
        }

#endregion

#region IPluginSerializable members

        public override void Serialize(Stream stream)
        {
        }

#endregion

        public virtual FilterCriteriaFacade GetTemplateCompatibleCriteriaFacade()
        {
            object newCriteria = TemplateCompatibleCriteria;
            FilterCriteriaFacade newCriteriaFacade;

            if (newCriteria is FilterCriteriaFacade)
            {
                newCriteriaFacade = newCriteria as FilterCriteriaFacade;
            }
            else
            {
                // Create proxy
                newCriteriaFacade = CreateProxyFilterCriteria(newCriteria);
            }

            return newCriteriaFacade;
        }

        public virtual FilterCriteriaFacade DeserializeCriteriaFacade(Stream stream, UInt16 version)
        {
            object deserializedCriteria = DeserializeCriteria(stream, version);
            FilterCriteriaFacade deserializedCriteriaFacade;

            if (deserializedCriteria is FilterCriteriaFacade)
            {
                deserializedCriteriaFacade = deserializedCriteria as FilterCriteriaFacade;
            }
            else
            {
                // Create proxy
                deserializedCriteriaFacade = CreateProxyFilterCriteria(deserializedCriteria);
            }

            return deserializedCriteriaFacade;
        }

        public virtual List<INamedZone> ConcreteNamedZones
        {
            get { return m_ConcreteNamedZones; }
        }

        public virtual FilterCriteriaFacade OnCriteriaSelected(FilterCriteriaFacade previousSelection)
        {
            object resultCriteria = OnSelectedInList(previousSelection);
            FilterCriteriaFacade resultFacade = null;

            if (resultCriteria is FilterCriteriaFacade)
            {
                resultFacade = resultCriteria as FilterCriteriaFacade;
            }
            else if (resultCriteria != null)
            {
                resultFacade = CreateProxyFilterCriteria(resultCriteria);
            }

            return resultFacade;
        }

        protected void TriggerNamedZonesListChanged()
        {
            if (NamedZonedListChanged != null)
            {
                NamedZonedListChanged(this, new PropertyChangedEventArgs("NamedZones"));
            }
        }

        public static FilterCriteriaFacade CreateProxyFilterCriteria(object criteria)
        {
            FilterCriteriaFacade result = null;

            try
            {
                result = new ProxyFilterCriteria(criteria);
            }
            catch (Exception e)
            {
                Debug.Assert(false, e.Message);
            }

            return result;
        }

        private INamedZone CreateProxyNamedZone(object namedZone)
        {
            try
            {
                return new ProxyNamedZone(namedZone);
            }
            catch (Exception e)
            {
                Debug.Assert(false, e.Message);
            }

            return null;
        }

        private void BuildConcreteNamedZones()
        {
            m_ConcreteNamedZones.Clear();

            if (NamedZones != null)
            {
                foreach (object namedZone in NamedZones)
                {
                    INamedZone concreteNamedZone = null;

                    if (namedZone is INamedZone)
                    {
                        concreteNamedZone = namedZone as INamedZone;
                    }
                    else
                    {
                        concreteNamedZone = CreateProxyNamedZone(namedZone);
                    }

                    if (concreteNamedZone != null)
                    {
                        m_ConcreteNamedZones.Add(concreteNamedZone);
                    }
                }
            }
        }

        private List<INamedZone> m_ConcreteNamedZones = new List<INamedZone>();
    }
}
